#include "EntityPlayer.h"
#include "ComponentManager.h"
#include <SDL.h>

#include <iostream>
using namespace std;

CEntityPlayer::CEntityPlayer(const CVector2i& startPosition, int speed, int idAnimWalkRight,
		int idAnimWalkLeft, int indexAnimIdleRight, int indexAnimIdleLeft, int indexAnimJumpRight, int indexAnimJumpLeft,
		int indexAnimAttackRight, int indexAnimAttackLeft)
	:CWorldEntity(0, startPosition, true), m_speed(speed), m_statePlayerAction(eStateStill), 
	m_timeStartJump(-1), m_durationJump(500), m_statePlayerDirection(eDirectionRight), m_idAnimWalkRight(idAnimWalkRight),
	m_idAnimWalkLeft(idAnimWalkLeft) ,m_animIdOfSprite(-1), m_animTime(-1), m_idAnimIdleLeft(indexAnimIdleLeft),
	m_idAnimIdleRight(indexAnimIdleRight), m_idAnimJumpLeft(indexAnimJumpLeft), m_idAnimJumpRight(indexAnimJumpRight),
	m_idAnimAttackLeft(indexAnimAttackLeft), m_idAnimAttackRight(indexAnimAttackRight), m_timeStartAttack(-1), 
	m_durationBetweenTwoAttack(200)
{
	m_rectangleCollision.setTop(0);
	m_rectangleCollision.setBottom(38);
	m_rectangleCollision.setLeft(0);
	m_rectangleCollision.setRight(30);

	m_vectorAction.resize(3);

	m_side = eSidePlayer;
}

CEntityPlayer::~CEntityPlayer(){};

void CEntityPlayer::doUpdate(void)
{
#ifdef _DEBUG
	CM.PROFILER().startCount("EntityPlayer Update");
#endif

	//apply the action that are in the vector
	if(m_vectorAction.size()!=0)
	{
		bool goThroughtMove = false;
		for(vector<eAction>::iterator i=m_vectorAction.begin(); i!=m_vectorAction.end(); i++)
		{
			switch(*i)
			{
				case eMoveLeft:
					movePlayerLeft();
					goThroughtMove=true;
					if(m_statePlayerAction!=eStateJumpUp && m_statePlayerAction!=eStateJumpDown)
						m_statePlayerAction=eStateMove;
					m_statePlayerDirection=eDirectionLeft;
					break;

				case eMoveRight:
					movePlayerRight();
					goThroughtMove=true;
					if(m_statePlayerAction!=eStateJumpUp && m_statePlayerAction!=eStateJumpDown)
						m_statePlayerAction=eStateMove;
					m_statePlayerDirection=eDirectionRight;
					break;

				case eJump:
					if(m_statePlayerAction!=eStateJumpUp && m_statePlayerAction!=eStateJumpDown)
					{
						resetAnimData();
						playerJumpUp();
						m_statePlayerAction=eStateJumpUp;
					}
					break;

				case eAttack:
					if(m_statePlayerAction != eStateJumpUp && m_statePlayerAction != eStateJumpDown 
						&& m_timeStartAttack==-1)
					{
						if(!goThroughtMove)
							m_statePlayerAction = eStateStill;

						m_timeStartAttack = SDL_GetTicks();
						attack();
					}
					break;

				default:
					m_statePlayerAction=eStateStill;
					break;
			}
		}
	}
	else
	{
		if(m_statePlayerAction!=eStateJumpUp && m_statePlayerAction!=eStateJumpDown)
			m_statePlayerAction=eStateStill;
	}

	//apply jump
	if(m_statePlayerAction==eStateJumpUp)
	{
		if(m_timeStartJump==-1)
			m_timeStartJump=SDL_GetTicks();

		if((int)(SDL_GetTicks())-m_timeStartJump<m_durationJump)
			playerJumpUp();
		else
		{
			m_timeStartJump=-1;
			m_statePlayerAction=eStateJumpDown;
		}
	}
	else if(m_statePlayerAction == eStateJumpDown)
		playerJumpDown();

	//count if the player can attack
	int m_currentTime = SDL_GetTicks();
	if(m_currentTime>m_timeStartAttack+m_durationBetweenTwoAttack)
		m_timeStartAttack=-1;

	//clear the vector of action
	m_vectorAction.clear();

	//check collision
	CWorldEntity* collidedWith = CM.WORLD().checkCollision(this);
	if(collidedWith!=0)
	{
		if(collidedWith->getSide()==eSideEnemy)
		{
			m_healthPoint-=collidedWith->getDamagePoint();
		}
		cout<<"ENTITY PLAYER : collision detected"<<endl;
		if(m_previousPosition.m_x<=320/3)
		{
			CM.WORLD().scrollWorld(CVector2i(-m_speed, 0));
			m_position.m_x+=m_speed;
		}
		else if(m_previousPosition.m_x>=320/3*2)
		{
			CM.WORLD().scrollWorld(CVector2i(m_speed, 0));
			m_position.m_x-=m_speed;
		}
		else
			m_position.setX(m_previousPosition.getX());
	}

	//apply gravity//
	//define the gravity vector
	const CVector2i gravity(0, 7);

	//save the previous position if dufferent of the current
	if(m_previousPosition != m_position)
		m_previousPosition = m_position;

	//apply gravity
	m_position=m_position+gravity;
	playerJumpDown();

	//check collision
	CWorldEntity* collisionEntity = CM.WORLD().checkCollision(this);
	if(collisionEntity!=0)
	{
		if(collisionEntity->getSide() == eSideEnemy)
			m_healthPoint-=collisionEntity->getDamagePoint();

		//get the height of the entity collided with
		int height=m_rectangleCollision.getBottom() - m_rectangleCollision.getTop();

		//get the top Y coordinate of the entity collided with
		int y=collisionEntity->getPosition().getY()-height;

		//set the position of the player
		m_position.setY(y-1);

		//if the player was in state jump down, there was a collision so we put it to state still
		if(m_statePlayerAction==eStateJumpDown)
			m_statePlayerAction=eStateStill;
		
	}
	else
	{
		if(m_statePlayerAction != eStateJumpUp)
			m_statePlayerAction=eStateJumpDown;
	}
	
	if(m_healthPoint<0)
		m_healthPoint = 0;

	//CM.SCENE().updateEntity(this);
#ifdef _DEBUG
	CM.PROFILER().endCount("EntityPlayer Update");
#endif
}

void CEntityPlayer::doRender(void)
{
	switch(m_statePlayerAction)
	{
		case eStateMove:
			if(m_statePlayerDirection==eDirectionRight)
				CM.VISU().displayAnimation(m_idAnimWalkRight, m_position, &m_animIdOfSprite, &m_animTime);
			else if (m_statePlayerDirection==eDirectionLeft)
				CM.VISU().displayAnimation(m_idAnimWalkLeft, m_position, &m_animIdOfSprite, &m_animTime);
			break;

		case eStateJumpUp:
			if(m_statePlayerDirection==eDirectionRight)
				CM.VISU().displayAnimation(m_idAnimJumpRight, m_position, &m_animIdOfSprite, &m_animTime);
			else
				CM.VISU().displayAnimation(m_idAnimJumpLeft, m_position, &m_animIdOfSprite, &m_animTime);
			break;

		case eStateJumpDown:
			if(m_statePlayerDirection==eDirectionRight)
				CM.VISU().displayAnimation(m_idAnimJumpRight, m_position, &m_animIdOfSprite, &m_animTime);
			else
				CM.VISU().displayAnimation(m_idAnimJumpLeft, m_position, &m_animIdOfSprite, &m_animTime);
			break;

		default:
			int indexAnimIdle;
			if(m_statePlayerDirection==eDirectionLeft)
				indexAnimIdle = m_idAnimIdleLeft;
			else
				indexAnimIdle = m_idAnimIdleRight;
			CM.VISU().displayAnimation(indexAnimIdle, m_position, &m_animIdOfSprite, &m_animTime);
			break;
	};

	
}

void CEntityPlayer::movePlayerLeft()
{
	//get the box where the player has to stay
	const int minTranslationX = 320/3;

	//save previous prosition
	if(m_previousPosition!=m_position)
		m_previousPosition=m_position;

	//calculate the new position on x axis
	m_position.m_x-=m_speed;

	//if the player is out of the box
	if(m_position.m_x<=minTranslationX)
	{
		//scroll the world
		CM.WORLD().scrollWorld(CVector2i(m_speed, 0));

		//decrease the previous position
		m_previousPosition.m_x-=m_speed;
	}
}

void CEntityPlayer::movePlayerRight()
{
	//get the box where the player has to stay
	const int maxTranslationX = 320/3*2;

	//save previous prosition
	if(m_previousPosition!=m_position)
		m_previousPosition=m_position;

	//calculate the new position on x axis
	m_position.m_x+=m_speed;

	//if the player is out of the box
	if(m_position.m_x>=maxTranslationX)
	{
		//scrolll the world
		CM.WORLD().scrollWorld(CVector2i(-m_speed, 0));
		m_previousPosition.m_x+=m_speed;
	}
}

void CEntityPlayer::playerJumpUp()
{
	//get the top of the box
	const int minTranslationY = 240/3;

	//move the player
	CVector2i offset(0, -14);
	m_position=m_position+offset;

	//if the player os out of the box
	if(m_position.m_y<=minTranslationY)
		CM.WORLD().scrollWorld(CVector2i(0, 7));//tranlsate the world
}

void CEntityPlayer::playerJumpDown()
{
	//get the bottom of the box
	const int maxTranslationY = 240/3*2-40;

	//if the player os out of the box
	if(m_position.m_y>=maxTranslationY)
		CM.WORLD().scrollWorld(CVector2i(0, -7));//translate the world
}

void CEntityPlayer::attack()
{
	CVector2i offset(30, 10);

	bool right = true;
	if(m_statePlayerDirection==eDirectionLeft)
	{
		right=false;
		offset.m_x=5;
	}

	if(right)
	{
		if(CM.PROJECTILE().activeProjectile(ePlayerProjectile, m_position+offset, right, eSidePlayer))
			CM.LOGCONSOLE().Log()<<"Projectile created\n";
		else
			CM.LOGCONSOLE().Log()<<"Projectile not created\n";
	}
	else
	{
		if(CM.PROJECTILE().activeProjectile(eEnemyProjectile, m_position+offset, right, eSidePlayer))
			CM.LOGCONSOLE().Log()<<"Projectile created\n";
		else
			CM.LOGCONSOLE().Log()<<"Projectile not created\n";
	}
}

void CEntityPlayer::addAction(eAction newAction)
{
	m_vectorAction.push_back(newAction);
}

void CEntityPlayer::resetAnimData(void)
{
	m_animIdOfSprite=-1;
	m_animTime=-1;
}
